#include <jni.h>
#include <signal.h>
#include <stdlib.h>
#include <android/log.h>
#include <stdbool.h>
#include "port.h"
#include "dvb.h"
#include"assert.h"
#include "ci.h"
#include "download.h"

#define CLASS_PATH "com/smit/dvb/jni/DVB"

#define LOG_TAG "DVB-CORE"


static JavaVM		*gs_jvm = NULL;
static jobject		gs_obj = NULL;

jclass DVBTunerInfoClass;
jclass DVBNetworkInfoClass;
jclass DVBServiceInfoClass;
jclass DVBTimeInfoClass;
jclass DVBEitInfoClass;
jclass DVBFreqInfoClass;
jclass DVBCiPinInfoClass;
jclass DVBCIMenuInfoClass;
jclass DVBCIDataClass;


int u32DebugOutputLevel = DVB_DEBUG_LEVEL_COMMON;

void DVB_DebugOutput(unsigned int u32Level, const char* ps8DebugString)
{
	if(u32Level == DVB_DEBUG_LEVEL_COMMON && u32DebugOutputLevel <= DVB_DEBUG_LEVEL_COMMON)
	{
		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%s", ps8DebugString);
	}
	else if(u32Level == DVB_DEBUG_LEVEL_ERROR && u32DebugOutputLevel <= DVB_DEBUG_LEVEL_ERROR)
	{
		__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", ps8DebugString);
	}
}

jobject getGlobalContext(JNIEnv *env) {
	jclass activityThread = (*env)->FindClass(env, "android/app/ActivityThread");

	jmethodID currentActivityThread = (*env)->GetStaticMethodID(env, activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;");

	jobject at = (*env)->CallStaticObjectMethod(env, activityThread, currentActivityThread);

	jmethodID getApplication = (*env)->GetMethodID(env, activityThread, "getApplication", "()Landroid/app/Application;");

	jobject context = (*env)->CallObjectMethod(env, at, getApplication);

	return context;
}

static char *getAppFilesDir(jobject context, JNIEnv *env,  char* ps8FilesDir, unsigned int u32DirLen) 
{
	jclass contextClass = (*env)->GetObjectClass(env, context);
	jmethodID methodGetFilesDir = (*env)->GetMethodID(env, contextClass, (char*)"getFilesDir", (char*)"()Ljava/io/File;");

	jobject fileObject = (*env)->CallObjectMethod(env, context, methodGetFilesDir);
	jclass fileClass = (*env)->FindClass(env, "java/io/File");
	jmethodID methodGetAbsolutePath = (*env)->GetMethodID(env, fileClass, (char*)"getAbsolutePath", (char*)"()Ljava/lang/String;");

	jstring filePath = (*env)->CallObjectMethod(env, fileObject, methodGetAbsolutePath);
	
	if (filePath != NULL) 
	{
		// get UTF8 string & copy to destconst
		char* charBuff = (char *)(*env)->GetStringUTFChars(env, filePath, NULL);
		strncpy(ps8FilesDir, charBuff, u32DirLen);
		(*env)->ReleaseStringUTFChars(env, filePath, charBuff);
		(*env)->DeleteLocalRef(env, filePath);
	}
	(*env)->DeleteLocalRef(env, contextClass);
	(*env)->DeleteLocalRef(env, fileObject);
	(*env)->DeleteLocalRef(env, fileClass);
	return ps8FilesDir;
}

int DVBHandleScanParam(JNIEnv *env, jmethodID callback, int msg, void* param)
{
	jobject object;
	dvb_tuner_t* pstTuner;
	dvb_network_t* pstNetwork;
	dvb_tuner_status_t* pstTunerStatus;
	dvb_process_t* pstProcess;
	builder_scan_services_t* pstServices;
	jclass clazz = NULL;
	jmethodID InitMethodID;

	mwDebug("DVBHandleScanParam() - entry, msg = %d\r\n", msg);
	switch(msg)
	{
		case MSG_SCAN_ERROR:
		{
			object = NULL;
			mwDebug("DVBHandleScanParam() - MSG_SCAN_ERROR call jniDVBCallback start\r\n");
			(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
			mwDebug("DVBHandleScanParam() - MSG_SCAN_ERROR call jniDVBCallback end\r\n");
			break;
		}
		case MSG_SCAN_START:			//dvb_tuner_t, com/smit/dvb/DVBTunerInfo
		{
			pstTuner = (dvb_tuner_t*)param;
			mwDebug("DVBHandleScanParam() - MSG_SCAN_START freq = %d\r\n", pstTuner->frequency);
			clazz = DVBTunerInfoClass;
			if(clazz)
			{
				jfieldID frequencyID = (*env)->GetFieldID(env, clazz, "frequency", "I");
				jfieldID symbolRateID = (*env)->GetFieldID(env, clazz, "symbolRate", "I");
				jfieldID modulationID = (*env)->GetFieldID(env, clazz, "modulation", "I");
				jfieldID bandWidthID = (*env)->GetFieldID(env, clazz, "bandWidth", "I");
				jfieldID lockStatusID = (*env)->GetFieldID(env, clazz, "lockStatus", "I");
				jfieldID levelID = (*env)->GetFieldID(env, clazz, "level", "I");
				jfieldID snrID = (*env)->GetFieldID(env, clazz, "snr", "I");
				jfieldID tunerTypeID = (*env)->GetFieldID(env, clazz, "tunerType", "I");

				InitMethodID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
				object = (*env)->NewObject(env, clazz, InitMethodID);
				if(object != NULL)
				{
					(*env)->SetIntField(env, object, frequencyID, pstTuner->frequency);
					(*env)->SetIntField(env, object, symbolRateID, pstTuner->symbol_rate);
					(*env)->SetIntField(env, object, modulationID, pstTuner->modulation);
					(*env)->SetIntField(env, object, bandWidthID, pstTuner->bandwidth);
					(*env)->SetIntField(env, object, lockStatusID, 0);
					(*env)->SetIntField(env, object, levelID, 0);
					(*env)->SetIntField(env, object, snrID, 0);
					(*env)->SetIntField(env, object, tunerTypeID, pstTuner->tunertype);
					(*env)->DeleteLocalRef(env, clazz);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_START call jniDVBCallback start\r\n");
					(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_START call jniDVBCallback end\r\n");
				}
			}
			else
			{
				mwDebug("DVBHandleScanParam() - found no com/smit/dvb/DVBTunerInfo class\r\n");
			}
			break;
		}
		case MSG_SCAN_DVB_NETWORK:		//dvb_network_t com/smit/dvb/DVBNetworkInfo
		{
			pstNetwork = (dvb_network_t*)param;
			mwDebug("DVBHandleScanParam() - MSG_SCAN_DVB_NETWORK name = %s\r\n", pstNetwork->m_as8NetworkName);
			clazz = DVBNetworkInfoClass;
			if(clazz)
			{
				jfieldID networkNameID = (*env)->GetFieldID(env, clazz, "networkName", "Ljava/lang/String;");
				jfieldID networkIdID = (*env)->GetFieldID(env, clazz, "networkId", "I");
				jstring str;
				if(pstNetwork->m_as8NetworkName[0] != 0)
					str = (*env)->NewStringUTF(env, pstNetwork->m_as8NetworkName);
				else
					str = NULL;
				InitMethodID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
				object = (*env)->NewObject(env, clazz, InitMethodID);
				if(object != NULL)
				{
					(*env)->SetObjectField(env, object, networkNameID, str);
					(*env)->SetIntField(env, object, networkIdID, pstNetwork->m_u32NetworkID);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_DVB_NETWORK call jniDVBCallback start\r\n");
					(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_DVB_NETWORK call jniDVBCallback end\r\n");
				}
				else
				{
					mwDebug("DVBHandleScanParam() - MSG_SCAN_DVB_NETWORK new object NULL\r\n");
				}
			}
			else
			{
				mwDebug("DVBHandleScanParam() - found no com/smit/dvb/DVBNetworkInfo class\r\n");
			}
			break;
		}
		case MSG_SCAN_TUNER_LOCKED:	//dvb_tuner_status_t  com/smit/dvb/DVBTunerInfo
		{
			pstTunerStatus = (dvb_tuner_status_t*)param;
			mwDebug("DVBHandleScanParam() - MSG_SCAN_TUNER_LOCKED bLock = %d\r\n", pstTunerStatus->bLock);
			clazz = DVBTunerInfoClass;
			if(clazz)
			{
				jfieldID frequencyID = (*env)->GetFieldID(env, clazz, "frequency", "I");
				jfieldID symbolRateID = (*env)->GetFieldID(env, clazz, "symbolRate", "I");
				jfieldID modulationID = (*env)->GetFieldID(env, clazz, "modulation", "I");
				jfieldID bandWidthID = (*env)->GetFieldID(env, clazz, "bandWidth", "I");
				jfieldID lockStatusID = (*env)->GetFieldID(env, clazz, "lockStatus", "I");
				jfieldID levelID = (*env)->GetFieldID(env, clazz, "level", "I");
				jfieldID snrID = (*env)->GetFieldID(env, clazz, "snr", "I");
				jfieldID tunerTypeID = (*env)->GetFieldID(env, clazz, "tunerType", "I");

				InitMethodID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
				object = (*env)->NewObject(env, clazz, InitMethodID);
				if(object != NULL)
				{
					(*env)->SetIntField(env, object, frequencyID, pstTunerStatus->frequency);
					(*env)->SetIntField(env, object, symbolRateID, pstTunerStatus->symbol_rate);
					(*env)->SetIntField(env, object, modulationID, pstTunerStatus->modulation);
					(*env)->SetIntField(env, object, bandWidthID, pstTunerStatus->bandwidth);
					(*env)->SetIntField(env, object, lockStatusID, pstTunerStatus->bLock);
					(*env)->SetIntField(env, object, levelID, pstTunerStatus->level);
					(*env)->SetIntField(env, object, snrID, pstTunerStatus->snr);
					//(*env)->SetIntField(env, ret, tunerTypeID, pstTunerStatus->tunertype);
					(*env)->DeleteLocalRef(env, clazz);	
					mwDebug("DVBHandleScanParam() - MSG_SCAN_TUNER_LOCKED call jniDVBCallback start\r\n");
					(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_TUNER_LOCKED call jniDVBCallback end\r\n");
				}
			}
			else
			{
				mwDebug("DVBHandleScanParam() - found no com/smit/dvb/DVBTunerInfo class\r\n");
			}
			break;
		}
		case MSG_SCAN_PROGRESS_CHANGED:	//dvb_process_t  java/lang/Integer 
		{
			pstProcess = (dvb_process_t*)param;
			mwDebug("DVBHandleScanParam() - MSG_SCAN_PROGRESS_CHANGED pstProcess = %d\r\n", pstProcess->m_u32Process);
			clazz = (*env)->FindClass(env, "java/lang/Integer");
			if(clazz)
			{
				InitMethodID = (*env)->GetMethodID(env, clazz, "<init>", "(I)V");
				if(InitMethodID)
				{
					object = (*env)->NewObject(env, clazz, InitMethodID, pstProcess->m_u32Process);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_PROGRESS_CHANGED call jniDVBCallback start\r\n");
					(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_PROGRESS_CHANGED call jniDVBCallback end\r\n");
				}
			}
			else
			{
				mwDebug("DVBHandleScanParam() - found no java/lang/Integer\r\n");
			}
			break;
		}
		case MSG_SCAN_SERVICES_FOUND:		//builder_scan_services_t; [com/smit/dvb/DVBServiceInfo 
		{
			pstServices = (builder_scan_services_t*)param;
			mwDebug("DVBHandleScanParam() - MSG_SCAN_SERVICES_FOUND cnt = %d\r\n", pstServices->m_u32Cnt);
			clazz = DVBServiceInfoClass;
			if(clazz)
			{
				unsigned int i;

				InitMethodID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
				object = (*env)->NewObjectArray(env, pstServices->m_u32Cnt, clazz, NULL);
				if(object)
				{
					jfieldID serviceIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceId", "I");
					jfieldID serviceTypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceType", "I");
					jfieldID serviceNameID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceName", "Ljava/lang/String;");
					jfieldID tsIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tsId", "I");
					jfieldID netIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "netId", "I");
					jfieldID freqID = (*env)->GetFieldID(env, DVBServiceInfoClass, "frequency", "I");
					jfieldID symID = (*env)->GetFieldID(env, DVBServiceInfoClass, "symbolRate", "I");
					jfieldID bandID = (*env)->GetFieldID(env, DVBServiceInfoClass, "bandWidth", "I");
					jfieldID modID = (*env)->GetFieldID(env, DVBServiceInfoClass, "modulation", "I");
					jfieldID tunertypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tunerType", "I");
					jfieldID isDescrambleID = (*env)->GetFieldID(env, DVBServiceInfoClass, "isDescramble", "Z");
					jfieldID isLockedID = (*env)->GetFieldID(env, DVBServiceInfoClass, "isLocked", "Z");
					jfieldID isUsedID = (*env)->GetFieldID(env, DVBServiceInfoClass, "isUsed", "I");
					jfieldID volumeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "volume", "I");
					jfieldID stereoModeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "stereoMode", "I");
					
					for(i=0; i<pstServices->m_u32Cnt; i++)
					{
						jobject objectElement = (*env)->NewObject(env, clazz, InitMethodID);

						(*env)->SetIntField(env, objectElement, serviceIdID, pstServices->m_pstServices[i].m_u16ServiceId);
						(*env)->SetIntField(env, objectElement, serviceTypeID, pstServices->m_pstServices[i].m_u8ServiceType);
						jstring str = (*env)->NewStringUTF(env, pstServices->m_pstServices[i].m_s8Name);
						(*env)->SetObjectField(env, objectElement, serviceNameID, str);
						(*env)->SetIntField(env, objectElement, tsIdID,  0);
						(*env)->SetIntField(env, objectElement, netIdID, 0);
						(*env)->SetIntField(env, objectElement, freqID, 0);
						(*env)->SetIntField(env, objectElement, symID, 0);
						(*env)->SetIntField(env, objectElement, bandID, 0);
						(*env)->SetIntField(env, objectElement, tunertypeID, 0);
						
						if(pstServices->m_pstServices[i].m_u8Encrypt== 1)
							(*env)->SetBooleanField(env, objectElement, isDescrambleID, true);
						else
							(*env)->SetBooleanField(env, objectElement, isDescrambleID, false);
						(*env)->SetBooleanField(env, objectElement, isLockedID, false);
						
						(*env)->SetIntField(env, objectElement, volumeID, 0);
						(*env)->SetIntField(env, objectElement, stereoModeID, 0);
												
						(*env)->SetObjectArrayElement(env, object, i, objectElement);
						(*env)->DeleteLocalRef(env, objectElement);	

						mwDebug("DVBHandleScanParam() - i = %d, name  %s, type = %d\r\n", i, pstServices->m_pstServices[i].m_s8Name, pstServices->m_pstServices[i].m_u8ServiceType);
					}
					mwDebug("DVBHandleScanParam() - MSG_SCAN_SERVICES_FOUND call jniDVBCallback start\r\n");
					(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
					mwDebug("DVBHandleScanParam() - MSG_SCAN_SERVICES_FOUND call jniDVBCallback end\r\n");
				}
			}
			else
			{
				mwDebug("DVBHandleScanParam() - found no com/smit/dvb/DVBServiceInfo\r\n");
			}
			break;
		}
		case MSG_SCAN_FINISH:
		{
			mwDebug("DVBHandleScanParam() - MSG_SCAN_FINISH\r\n");
			object = NULL;
			(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
			mwDebug("DVBHandleScanParam() - MSG_SCAN_FINISH call jniDVBCallback end\r\n");
			break;
		}
		default:
		{
			object = NULL;
			mwError("DVBHandleScanParam() - found msg = %d error\r\n", msg);
			//(*env)->CallVoidMethod(env, gs_obj, callback, DVB_CB_TYPE_SCAN, msg, object);
			//mwDebug("DVBHandleScanParam() - MSG_SCAN_FINISH call jniDVBCallback end\r\n");
			break;
		}
	}
	mwDebug("DVBHandleScanParam() - return\r\n");
}

int DVBCallback(DVB_CB_TYPE_T eType, int msg, void* param)
{
	int s32Ret = 0;
	JNIEnv *env = NULL;
	jclass clazz = NULL;
	jmethodID callback= NULL;
	jobject object = NULL;

	if((*gs_jvm)->AttachCurrentThread(gs_jvm,&env, NULL))
	{
		mwError("DVBCallback() - AttachCurrentThread error\r\n");
		return -1;
	}

	clazz = (*env)->GetObjectClass(env, gs_obj);
	if (NULL == clazz)
	{
		return -1;
	}
	callback  = (*env)->GetMethodID(env,clazz,"jniDVBCallback", "(IILjava/lang/Object;)V");
	if(callback == NULL)
	{
		mwError("DVBCallback() - found jniDVBCallback NULL\r\n");
		return -1;
	}

	switch(eType)
	{
		case DVB_CB_TYPE_CI:
		{
			mwDebug("DVBCallback() - get DVB_CB_TYPE_CI msg = %d\r\n", msg);
			(*env)->CallVoidMethod(env, gs_obj, callback, eType, msg, object);
			break;
		}
		case DVB_CB_TYPE_EPG:
		{
			
			break;
		}
		case DVB_CB_TYPE_SCAN:
		{
			DVBHandleScanParam(env, callback, msg, param);
			break;
		}
		case DVB_CB_TYPE_SERVICE:
		{
			mwDebug("DVBCallback() - get DVB_CB_TYPE_SERVICE msg = %d\r\n", msg);
			(*env)->CallVoidMethod(env, gs_obj, callback, eType, msg, object);
			break;
		}
		case DVB_CB_TYPE_SETUP:
		{
			
			break;
		}
		case DVB_CB_TYPE_SYSTEM:
		{
			mwDebug("DVBCallback() - get DVB_CB_TYPE_SYSTEM, msg = %d\r\n", msg);
			(*env)->CallVoidMethod(env, gs_obj, callback, eType, msg, object);
			break;
		}
		case DVB_CB_TYPE_UPDATE:
		{
			
			jint jRequestInfoLen = strlen(param);
			jstring jRequestInfo = NULL;
			mwDebug("DVBCallback() - get DVB_CB_TYPE_UPDATE, msg = %d\r\n", msg);
			mwDebug("DVBCallback() - get DVB_CB_TYPE_UPDATE, jRequestInfoLen = %d\r\n", jRequestInfoLen);
			mwDebug("DVBCallback() - get DVB_CB_TYPE_UPDATE, param = %s\r\n", param);
			jRequestInfo = (*env)->NewStringUTF(env, param);
			(*env)->CallVoidMethod(env, gs_obj, callback, eType, msg, jRequestInfo);
			(*env)->DeleteLocalRef(env, jRequestInfo);
			break;
		}
		default:
			break;
	}
	if((*gs_jvm)->DetachCurrentThread(gs_jvm)){
		mwError("DVBCallback() - DetachCurrentThread error\r\n");
		return -1;
	}

	return s32Ret;
}

jint DVB_SetServiceGroupId(JNIEnv* env, jobject clazz, jint groupId)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_SetServiceGroupId() - entry\r\n");
	
	ret = DVBSetServiceGroupId(groupId);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_SetServiceGroupId() - return\r\n");
	return ret;
}

jint DVB_GetServiceGroupId(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	unsigned int u32GroupId;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetServiceGroupId() - entry\r\n");

	ret = DVBGetServiceGroupId(&u32GroupId);
	if(ret == 0)
	{
		ret = u32GroupId;
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetServiceGroupId() - DVBGetServiceGroupId error\r\n");
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetServiceGroupId() - return\r\n");
	
	return ret;
}

jint DVB_RestoreSettings(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_RestoreSettings() - entry\r\n");
	ret = DVBRestoreSettings();
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_RestoreSettings() - return\r\n");
	return ret;
}

jobject DVB_GetDVBTime(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	dvb_time_t stTime;
	jobject timeObj = NULL;
	jmethodID InitMethodID;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetDVBTime() - entry\r\n");
	stTime = DVBGetDVBTime();
	if(DVBTimeInfoClass)
	{
		InitMethodID = (*env)->GetMethodID(env, DVBTimeInfoClass, "<init>", "()V");
		timeObj = (*env)->NewObject(env, DVBTimeInfoClass, InitMethodID);
		if(timeObj != NULL)
		{
			jfieldID yearID = (*env)->GetFieldID(env, DVBTimeInfoClass, "year", "I");
			jfieldID monthID = (*env)->GetFieldID(env, DVBTimeInfoClass, "month", "I");
			jfieldID mdayID = (*env)->GetFieldID(env, DVBTimeInfoClass, "mday", "I");
			jfieldID wdayID = (*env)->GetFieldID(env, DVBTimeInfoClass, "wday", "I");
			jfieldID hourID = (*env)->GetFieldID(env, DVBTimeInfoClass, "hour", "I");
			jfieldID minuteID = (*env)->GetFieldID(env, DVBTimeInfoClass, "minute", "I");
			jfieldID secondID = (*env)->GetFieldID(env, DVBTimeInfoClass, "second", "I");

			(*env)->SetIntField(env, timeObj, yearID, stTime.year);
			(*env)->SetIntField(env, timeObj, monthID, stTime.month);
			(*env)->SetIntField(env, timeObj, mdayID, stTime.mday);
			(*env)->SetIntField(env, timeObj, wdayID, stTime.wday);
			(*env)->SetIntField(env, timeObj, hourID, stTime.hour);
			(*env)->SetIntField(env, timeObj, minuteID, stTime.minute);
			(*env)->SetIntField(env, timeObj, secondID, stTime.second);
			(*env)->DeleteLocalRef(env, DVBTimeInfoClass);		
		}
		else
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetDVBTime() - create DVBTimeInfo object failed\r\n");
		}
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetDVBTime() - get class DVBTimeInfo failed\r\n");
	}
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetDVBTime() - return\r\n");
	return timeObj;	
}

jobject DVB_GetAllServices(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	dvb_service_info_t * pstServices;
	unsigned int u32ServiceCnt;
	jobjectArray SerivceObjArray = NULL;
	unsigned int i;
	jmethodID InitMethodID;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetAllServices() - entry\r\n");
	if(DVBServiceInfoClass)
	{
		jfieldID serviceIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceId", "I");
		jfieldID serviceTypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceType", "I");
		jfieldID serviceNameID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceName", "Ljava/lang/String;");
		jfieldID tsIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tsId", "I");
		jfieldID netIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "netId", "I");
		jfieldID freqID = (*env)->GetFieldID(env, DVBServiceInfoClass, "frequency", "I");
		jfieldID symID = (*env)->GetFieldID(env, DVBServiceInfoClass, "symbolRate", "I");
		jfieldID bandID = (*env)->GetFieldID(env, DVBServiceInfoClass, "bandWidth", "I");
		jfieldID modID = (*env)->GetFieldID(env, DVBServiceInfoClass, "modulation", "I");
		jfieldID tunertypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tunerType", "I");
		jfieldID isDescrambleID = (*env)->GetFieldID(env, DVBServiceInfoClass, "isDescramble", "Z");
		jfieldID isLockedID = (*env)->GetFieldID(env, DVBServiceInfoClass, "isLocked", "Z");
		jfieldID isUsedID = (*env)->GetFieldID(env, DVBServiceInfoClass, "isUsed", "I");
		jfieldID volumeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "volume", "I");
		jfieldID stereoModeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "stereoMode", "I");
		jfieldID channelNumberID = (*env)->GetFieldID(env, DVBServiceInfoClass, "channelNumber", "I");

		InitMethodID = (*env)->GetMethodID(env, DVBServiceInfoClass, "<init>", "()V");
		u32ServiceCnt = 0;
		DVBGetAllServices(NULL, &u32ServiceCnt);
		if(u32ServiceCnt > 0)
		{
			pstServices = mwOsAllocMemory(u32ServiceCnt*sizeof(dvb_service_info_t));
			if(pstServices)
			{
				DVBGetAllServices(pstServices, &u32ServiceCnt);
				SerivceObjArray = (*env)->NewObjectArray(env, u32ServiceCnt, DVBServiceInfoClass, NULL);
				if(SerivceObjArray == NULL)
				{
					DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetAllServices() - new SerivceObjArray failed\r\n ");
					mwOsFreeMemory(pstServices);
					return NULL;
				}
				for(i=0; i<u32ServiceCnt; i++)
				{
					jobject ServiceObj = (*env)->NewObject(env, DVBServiceInfoClass, InitMethodID);
					if(ServiceObj == NULL)
					{
						DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetScheduleInfo() - new EitObj failed\r\n");
						mwOsFreeMemory(pstServices);
						return NULL;
					}

					mwDebug("DVB_GetAllServices() - index %d, name %s\r\n", i, pstServices[i].m_as8ServiceName);
					
					(*env)->SetIntField(env, ServiceObj, serviceIdID, pstServices[i].m_u16ServiceID);
					(*env)->SetIntField(env, ServiceObj, serviceTypeID, pstServices[i].m_u32ServiceType);
					jstring str = (*env)->NewStringUTF(env, pstServices[i].m_as8ServiceName);
					(*env)->SetObjectField(env, ServiceObj, serviceNameID, str);
					(*env)->SetIntField(env, ServiceObj, tsIdID,  pstServices[i].m_u16TsID);
					(*env)->SetIntField(env, ServiceObj, netIdID, pstServices[i].m_u16NetID);
					(*env)->SetIntField(env, ServiceObj, freqID, pstServices[i].m_u32Freq);
					(*env)->SetIntField(env, ServiceObj, symID, pstServices[i].m_u32Sym);
					(*env)->SetIntField(env, ServiceObj, bandID, pstServices[i].m_u32Band);
					(*env)->SetIntField(env, ServiceObj, tunertypeID, pstServices[i].m_u32TunerType);
					
					if(pstServices[i].m_u32IsDescramble == 1)
						(*env)->SetBooleanField(env, ServiceObj, isDescrambleID, true);
					else
						(*env)->SetBooleanField(env, ServiceObj, isDescrambleID, false);
					if(pstServices[i].m_u32IsLocked == 1)
						(*env)->SetBooleanField(env, ServiceObj, isLockedID, true);
					else
						(*env)->SetBooleanField(env, ServiceObj, isLockedID, false);
					
					(*env)->SetIntField(env, ServiceObj, volumeID, pstServices[i].m_u32Volume);
					(*env)->SetIntField(env, ServiceObj, stereoModeID, pstServices[i].m_u32StereoMode);
					(*env)->SetIntField(env, ServiceObj, channelNumberID, pstServices[i].m_u32ChannelNumber);
					
					(*env)->SetObjectArrayElement(env, SerivceObjArray, i, ServiceObj);
					(*env)->DeleteLocalRef(env, ServiceObj);	

				}
			}
			else
			{
				DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetAllServices() - malloc failed\r\n");
			}
		}
	}
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetAllServices() - return\r\n");
	return SerivceObjArray;
}

jint DVB_ManualTune(JNIEnv* env, jobject clazz, jobject tunerInfo)
{
	jint ret = 0;
	jclass DVBTunerInfoClass;
	dvb_tuner_t stTunerInfo;

	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ManualTune() - entry\r\n");

	DVBTunerInfoClass = (*env)->GetObjectClass(env, tunerInfo);
	if(DVBTunerInfoClass)
	{
		jfieldID frequencyID = (*env)->GetFieldID(env, DVBTunerInfoClass, "frequency", "I");
		jfieldID symID = (*env)->GetFieldID(env, DVBTunerInfoClass, "symbolRate", "I");
		jfieldID modID = (*env)->GetFieldID(env, DVBTunerInfoClass, "modulation", "I");
		jfieldID bandWidthID = (*env)->GetFieldID(env, DVBTunerInfoClass, "bandWidth", "I");
		jfieldID tunerTypeID = (*env)->GetFieldID(env, DVBTunerInfoClass, "tunerType", "I");

		jint frequency = (*env)->GetIntField(env, tunerInfo, frequencyID);
		jint sym = (*env)->GetIntField(env, tunerInfo, symID);
		jint mod = (*env)->GetIntField(env, tunerInfo, modID);
		jint bandwidth = (*env)->GetIntField(env, tunerInfo, bandWidthID);
		jint type = (*env)->GetIntField(env, tunerInfo, tunerTypeID);
		
		stTunerInfo.frequency = frequency;
		stTunerInfo.symbol_rate = sym;
		stTunerInfo.modulation = mod;
		stTunerInfo.bandwidth = bandwidth;
		stTunerInfo.tunertype = type;

		ret = DVBManualTune(&stTunerInfo);
		
		(*env)->DeleteLocalRef(env, DVBTunerInfoClass);
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ManualTune() - find GetObjectClass failed\r\n ");
		ret = -1;
	}

	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ManualTune() - return\r\n");
	return ret;	
}

void DVB_StartImportServices(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_StartImportServices() - entry\r\n");
	
	DVBStartImportServices();
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_StartImportServices() - return\r\n");
	return;	
}

jint DVB_ImportServices(JNIEnv* env, jobject clazz, jobjectArray progs, jint sizes, jint groupIndex, jstring groupName)
{
	jint ret = 0;
	int len;
	dvb_networt_service_t* pstProglist;
	int i,serviceid,tsid,orgnetid,sym,mod,freq,tunertype;
	jstring programName;
	int programNameLen;
	const char *name;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ImportServices() - entry\r\n");
	name = (groupName == 0) ? 0 :  (char *)(*env)->GetStringUTFChars(env,groupName,NULL);
	len = (*env)->GetArrayLength(env, progs);
	if(DVBServiceInfoClass == NULL || len != sizes)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_ImportServices() - find class DVBServiceInfo failed\r\n");
		return -1;
	}

	pstProglist = (dvb_networt_service_t*)malloc(len*sizeof(dvb_networt_service_t));
	if(pstProglist == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_ImportServices() - malloc pstProglist failed\r\n");
		return -1;
	}

	jfieldID serviceidID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceId", "I");
	jfieldID tsidID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tsId", "I");
	jfieldID orgnetidID = (*env)->GetFieldID(env, DVBServiceInfoClass, "netId", "I");
	jfieldID symID = (*env)->GetFieldID(env, DVBServiceInfoClass, "symbolRate", "I");
	jfieldID modID = (*env)->GetFieldID(env, DVBServiceInfoClass, "modulation", "I");
	jfieldID freqID = (*env)->GetFieldID(env, DVBServiceInfoClass, "frequency", "I");
	jfieldID tunertypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tunerType", "I");
	jfieldID serviceTypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceType", "I");
	jfieldID serviceNameID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceName", "Ljava/lang/String;");

	for(i=0; i<len; i++)
	{
		jobject obj=(*env)->GetObjectArrayElement(env, progs, i);

		serviceid = (*env)->GetIntField(env, obj, serviceidID);
		tsid = (*env)->GetIntField(env, obj, tsidID);
		orgnetid = (*env)->GetIntField(env, obj, orgnetidID);
		sym = (*env)->GetIntField(env, obj, symID);
		mod = (*env)->GetIntField(env, obj, modID);
		freq = (*env)->GetIntField(env, obj, freqID);
		tunertype = (*env)->GetIntField(env, obj, tunertypeID);
		programName = (jstring)(*env)->GetObjectField(env, obj, serviceNameID);

		pstProglist[i].serviceid = serviceid;
		pstProglist[i].tsid = tsid;
		pstProglist[i].orgnetid = orgnetid;
		pstProglist[i].sym = sym;
		pstProglist[i].mod = mod;
		pstProglist[i].freq = freq;
		pstProglist[i].tunertype = tunertype;

		char *ptr = (char *)(*env)->GetStringUTFChars(env,programName,NULL);
		programNameLen = strlen(ptr);
		if(programNameLen >= sizeof(pstProglist[i].name))
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_ImportServices() - error programNameLen >= 32\n");
			programNameLen = sizeof(pstProglist[i].name) - 1;
		}
		memset(pstProglist[i].name, 0, sizeof(pstProglist[i].name));
		memcpy(pstProglist[i].name, ptr, programNameLen);

		(*env)->ReleaseStringUTFChars(env, programName, ptr);
		(*env)->DeleteLocalRef(env, obj);
		(*env)->DeleteLocalRef(env, programName);
	}

	DVBImportServices(pstProglist, len, groupIndex, name);
	free(pstProglist);
	(*env)->DeleteLocalRef(env, DVBServiceInfoClass);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ImportServices() - return\r\n");
	return ret;
}

void DVB_FinishImportServices(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_FinishImportServices() - entry\r\n");
	
	DVBFinishImportServices();
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_FinishImportServices() - return\r\n");
	return;
}

jint DVB_ManualScan(JNIEnv* env, jobject clazz, jobject tunerInfo)
{
	jint ret = 0;
	jclass DVBTunerInfoClass;
	dvb_tuner_t stTunerInfo;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ManualScan() - entry\r\n");

	DVBTunerInfoClass = (*env)->GetObjectClass(env, tunerInfo);
	if(DVBTunerInfoClass)
	{
		jfieldID frequencyID = (*env)->GetFieldID(env, DVBTunerInfoClass, "frequency", "I");
		jfieldID symID = (*env)->GetFieldID(env, DVBTunerInfoClass, "symbolRate", "I");
		jfieldID modID = (*env)->GetFieldID(env, DVBTunerInfoClass, "modulation", "I");
		jfieldID bandWidthID = (*env)->GetFieldID(env, DVBTunerInfoClass, "bandWidth", "I");
		jfieldID tunerTypeID = (*env)->GetFieldID(env, DVBTunerInfoClass, "tunerType", "I");

		jint frequency = (*env)->GetIntField(env, tunerInfo, frequencyID);
		jint sym = (*env)->GetIntField(env, tunerInfo, symID);
		jint mod = (*env)->GetIntField(env, tunerInfo, modID);
		jint bandwidth = (*env)->GetIntField(env, tunerInfo, bandWidthID);
		jint type = (*env)->GetIntField(env, tunerInfo, tunerTypeID);
		
		stTunerInfo.frequency = frequency;
		stTunerInfo.symbol_rate = sym;
		stTunerInfo.modulation = mod;
		stTunerInfo.bandwidth = bandwidth;
		stTunerInfo.tunertype = type;

		ret = DVBManualScan(&stTunerInfo);
		
		gs_obj = (*env)->NewGlobalRef(env,clazz);
		(*env)->DeleteLocalRef(env, DVBTunerInfoClass);
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ManualScan() - find GetObjectClass failed\r\n ");
		ret = -1;
	}

	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_ManualScan() - return\r\n");
	return ret;
}

jint DVB_AutoScan(JNIEnv* env, jobject clazz, jint startFreq, jint endFreq)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_AutoScan() - entry\r\n");
	
	ret = DVBAutoScan(startFreq, endFreq);
	gs_obj = (*env)->NewGlobalRef(env,clazz);
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_AutoScan() - return\r\n");
	return ret;	
}

jint DVB_FullScan(JNIEnv* env, jobject clazz, jint startFreq, jint endFreq)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_FullScan() - entry\r\n");

	ret = DVBFullScan(startFreq, endFreq);
	gs_obj = (*env)->NewGlobalRef(env,clazz);
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_FullScan() - return\r\n");
	return ret;	
}

jint DVB_AbortScan(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_AbortScan() - entry\r\n");
	
	ret = DVBAbortScan();
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_AbortScan() - return\r\n");
	return ret;		
}
jint DVB_PlayServiceByIndex(JNIEnv* env, jobject clazz, jint index)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_PlayServiceByIndex() - entry\r\n");
	
	ret = DVBPlayServiceByIndex(index);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_PlayServiceByIndex() - return\r\n");
	return ret;
}

jobject DVB_GetEitInfo(JNIEnv* env, jobject clazz, jobject serviceInfo, jint type)
{
	jint ret = 0;
	dvb_event_t stEvent;
	dvb_service_t stService;
	jobject EitObj;
	jmethodID DVBTimeInfoInitMethodID;
	jmethodID DVBEitInfoInitMethodID;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetEitInfo() - entry\r\n");
	if(DVBEitInfoClass && DVBTimeInfoClass)
	{
		jfieldID serviceIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceId", "I");
		jfieldID tsIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tsId", "I");
		jfieldID netIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "netId", "I");
		jfieldID freqID = (*env)->GetFieldID(env, DVBServiceInfoClass, "frequency", "I");
		jfieldID tunertypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tunerType", "I");

		DVBEitInfoInitMethodID = (*env)->GetMethodID(env, DVBEitInfoClass, "<init>", "()V");
		DVBTimeInfoInitMethodID = (*env)->GetMethodID(env, DVBTimeInfoClass, "<init>", "()V");
		
		stService.frequence = (*env)->GetIntField(env, serviceInfo, freqID);
		stService.netId = (*env)->GetIntField(env, serviceInfo, netIdID);
		stService.serviceId = (*env)->GetIntField(env, serviceInfo, serviceIdID);
		stService.tsId = (*env)->GetIntField(env, serviceInfo, tsIdID);

		ret = DVBGetEitInfo(&stService, type, &stEvent);
		if(ret == 0)
		{
			EitObj = (*env)->NewObject(env, DVBEitInfoClass, DVBEitInfoInitMethodID);
			if(EitObj == NULL)
			{
				DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - new DVBEitInfoClass object failed\r\n");
				return NULL;
			}
			jfieldID eventIdID = (*env)->GetFieldID(env, DVBEitInfoClass, "eventId", "I");
			(*env)->SetIntField(env, EitObj, eventIdID, stEvent.event_id);
			
			jfieldID startTimeID = (*env)->GetFieldID(env, DVBEitInfoClass, "startTime", "Lcom/smit/dvb/DVBTimeInfo;");
			jfieldID endTimeID = (*env)->GetFieldID(env, DVBEitInfoClass, "endTime", "Lcom/smit/dvb/DVBTimeInfo;");
			jfieldID yearID = (*env)->GetFieldID(env, DVBTimeInfoClass, "year", "I");
			jfieldID monthID = (*env)->GetFieldID(env, DVBTimeInfoClass, "month", "I");
			jfieldID mdayID = (*env)->GetFieldID(env, DVBTimeInfoClass, "mday", "I");
			jfieldID wdayID = (*env)->GetFieldID(env, DVBTimeInfoClass, "wday", "I");
			jfieldID hourID = (*env)->GetFieldID(env, DVBTimeInfoClass, "hour", "I");
			jfieldID minuteID = (*env)->GetFieldID(env, DVBTimeInfoClass, "minute", "I");
			jfieldID secondID = (*env)->GetFieldID(env, DVBTimeInfoClass, "second", "I");
			
			jobject startTimeObj = (*env)->NewObject(env, DVBTimeInfoClass, DVBTimeInfoInitMethodID);
			if(startTimeObj == NULL)
			{
				DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - new startTimeObj failed\r\n");
				return NULL;
			}
			
			(*env)->SetIntField(env, startTimeObj, yearID, stEvent.StartTime.year);
			(*env)->SetIntField(env, startTimeObj, monthID, stEvent.StartTime.month);
			(*env)->SetIntField(env, startTimeObj, mdayID,  stEvent.StartTime.mday);
			(*env)->SetIntField(env, startTimeObj, wdayID, stEvent.StartTime.wday);
			(*env)->SetIntField(env, startTimeObj, hourID, stEvent.StartTime.hour);
			(*env)->SetIntField(env, startTimeObj, minuteID, stEvent.StartTime.minute);
			(*env)->SetIntField(env, startTimeObj, secondID, stEvent.StartTime.second);
			(*env)->SetObjectField(env, EitObj, startTimeID, startTimeObj);
			
			jobject endTimeObj = (*env)->NewObject(env, DVBTimeInfoClass, DVBTimeInfoInitMethodID);
			if(endTimeObj == NULL)
			{
				DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - new endTimeObj failed\r\n");
				return NULL;
			}
			(*env)->SetIntField(env, endTimeObj, yearID, stEvent.EndTime.year);
			(*env)->SetIntField(env, endTimeObj, monthID, stEvent.EndTime.month);
			(*env)->SetIntField(env, endTimeObj, mdayID, stEvent.EndTime.mday);
			(*env)->SetIntField(env, endTimeObj, wdayID, stEvent.EndTime.wday);
			(*env)->SetIntField(env, endTimeObj, hourID, stEvent.EndTime.hour);
			(*env)->SetIntField(env, endTimeObj, minuteID, stEvent.EndTime.minute);
			(*env)->SetIntField(env, endTimeObj, secondID, stEvent.EndTime.second);
			(*env)->SetObjectField(env, EitObj, endTimeID, endTimeObj);

			jfieldID durationID = (*env)->GetFieldID(env, DVBEitInfoClass, "duration", "I");
			(*env)->SetIntField(env, EitObj, durationID, stEvent.duration);
			
			jstring str1 = (*env)->NewStringUTF(env, stEvent.lang);
			jfieldID langID = (*env)->GetFieldID(env, DVBEitInfoClass, "lang", "Ljava/lang/String;");
			(*env)->SetObjectField(env, EitObj, langID, str1);
			(*env)->DeleteLocalRef(env, str1);		
			
			str1 = (*env)->NewStringUTF(env, stEvent.EventName);
			jfieldID EventNameID = (*env)->GetFieldID(env, DVBEitInfoClass, "EventName", "Ljava/lang/String;");
			(*env)->SetObjectField(env, EitObj, EventNameID, str1);
			(*env)->DeleteLocalRef(env, str1);		
			
			str1 = (*env)->NewStringUTF(env, stEvent.Desc);
			jfieldID DescID = (*env)->GetFieldID(env, DVBEitInfoClass, "Desc", "Ljava/lang/String;");
			(*env)->SetObjectField(env, EitObj, DescID, str1);
			(*env)->DeleteLocalRef(env, str1);		
			
			str1 = (*env)->NewStringUTF(env, stEvent.ExtendDesc);
			jfieldID ExtendDescID = (*env)->GetFieldID(env, DVBEitInfoClass, "ExtendDesc", "Ljava/lang/String;");
			(*env)->SetObjectField(env, EitObj, ExtendDescID, str1);
			(*env)->DeleteLocalRef(env, str1);		
			
			jfieldID running_statusID = (*env)->GetFieldID(env, DVBEitInfoClass, "running_status", "I");
			(*env)->SetIntField(env, EitObj, running_statusID, (jint)stEvent.running_status);
			
			(*env)->DeleteLocalRef(env, DVBTimeInfoClass);		
			(*env)->DeleteLocalRef(env, DVBEitInfoClass);		
			(*env)->DeleteLocalRef(env, startTimeObj);		
			(*env)->DeleteLocalRef(env, endTimeObj);		
		}
		else
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - call DVBGetEitInfo return failed\r\n");
		}
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - get DVBServiceInfo class failed\r\n");
	}

	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetEitInfo() - return\r\n");
	return EitObj;
}

jobject DVB_GetScheduleInfo(JNIEnv* env, jobject clazz, jobject serviceInfo)
{
	jint ret = 0;
	dvb_event_t* pstEvent;
	dvb_service_t stService;
	jobject EitObjArray = NULL;
	unsigned int u32EventCnt;
	unsigned int i;
	jmethodID DVBTimeInfoInitMethodID;
	jmethodID DVBEitInfoInitMethodID;

	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetScheduleInfo() - entry\r\n");
	if(DVBServiceInfoClass && DVBEitInfoClass)
	{
		jfieldID serviceIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "serviceId", "I");
		jfieldID tsIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tsId", "I");
		jfieldID netIdID = (*env)->GetFieldID(env, DVBServiceInfoClass, "netId", "I");
		jfieldID freqID = (*env)->GetFieldID(env, DVBServiceInfoClass, "frequency", "I");
		jfieldID tunertypeID = (*env)->GetFieldID(env, DVBServiceInfoClass, "tunerType", "I");

		DVBEitInfoInitMethodID = (*env)->GetMethodID(env, DVBEitInfoClass, "<init>", "()V");
		DVBTimeInfoInitMethodID = (*env)->GetMethodID(env, DVBTimeInfoClass, "<init>", "()V");
		
		stService.frequence = (*env)->GetIntField(env, serviceInfo, freqID);
		stService.netId = (*env)->GetIntField(env, serviceInfo, netIdID);
		stService.serviceId = (*env)->GetIntField(env, serviceInfo, serviceIdID);
		stService.tsId = (*env)->GetIntField(env, serviceInfo, tsIdID);

		ret = DVBGetScheduleInfo(&stService, NULL, &u32EventCnt);
		if(ret == 0)
		{
			pstEvent = (dvb_event_t*)malloc(sizeof(dvb_event_t)*u32EventCnt);
			if(pstEvent)
			{					
				jobjectArray EitObjArray = (*env)->NewObjectArray(env, u32EventCnt, DVBEitInfoClass, NULL);
				if(EitObjArray == NULL)
				{
					DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetScheduleInfo() - new EitObjArray failed\r\n");
					free(pstEvent);
					return NULL;
				}
				for(i=0; i<u32EventCnt; i++)
				{

					jobject EitObj = (*env)->NewObject(env, DVBEitInfoClass, DVBEitInfoInitMethodID);
					if(EitObj == NULL)
					{
						DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetScheduleInfo() - new EitObj failed\r\n");
						free(pstEvent);
						return NULL;
					}

					jfieldID eventIdID = (*env)->GetFieldID(env, DVBEitInfoClass, "eventId", "I");
					(*env)->SetIntField(env, EitObj, eventIdID, pstEvent[i].event_id);
					
					jfieldID startTimeID = (*env)->GetFieldID(env, DVBEitInfoClass, "startTime", "Lcom/smit/dvb/DVBTimeInfo;");
					jfieldID endTimeID = (*env)->GetFieldID(env, DVBEitInfoClass, "endTime", "Lcom/smit/dvb/DVBTimeInfo;");
					
					jfieldID yearID = (*env)->GetFieldID(env, DVBTimeInfoClass, "year", "I");
					jfieldID monthID = (*env)->GetFieldID(env, DVBTimeInfoClass, "month", "I");
					jfieldID mdayID = (*env)->GetFieldID(env, DVBTimeInfoClass, "mday", "I");
					jfieldID wdayID = (*env)->GetFieldID(env, DVBTimeInfoClass, "wday", "I");
					jfieldID hourID = (*env)->GetFieldID(env, DVBTimeInfoClass, "hour", "I");
					jfieldID minuteID = (*env)->GetFieldID(env, DVBTimeInfoClass, "minute", "I");
					jfieldID secondID = (*env)->GetFieldID(env, DVBTimeInfoClass, "second", "I");
					
					jobject startTimeObj = (*env)->NewObject(env, DVBTimeInfoClass, DVBTimeInfoInitMethodID);
					if(startTimeObj == NULL)
					{
						DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetScheduleInfo() - new startTimeObj failed\r\n");
						free(pstEvent);
						return NULL;
					}
					
					(*env)->SetIntField(env, startTimeObj, yearID, pstEvent[i].StartTime.year);
					(*env)->SetIntField(env, startTimeObj, monthID, pstEvent[i].StartTime.month);
					(*env)->SetIntField(env, startTimeObj, mdayID,  pstEvent[i].StartTime.mday);
					(*env)->SetIntField(env, startTimeObj, wdayID, pstEvent[i].StartTime.wday);
					(*env)->SetIntField(env, startTimeObj, hourID, pstEvent[i].StartTime.hour);
					(*env)->SetIntField(env, startTimeObj, minuteID, pstEvent[i].StartTime.minute);
					(*env)->SetIntField(env, startTimeObj, secondID, pstEvent[i].StartTime.second);
					(*env)->SetObjectField(env, EitObj, startTimeID, startTimeObj);
					
					jobject endTimeObj = (*env)->NewObject(env, DVBTimeInfoClass, DVBTimeInfoInitMethodID);
					if(endTimeObj == NULL)
					{
						DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - new endTimeObj failed\r\n");
						free(pstEvent);
						return NULL;
					}
					(*env)->SetIntField(env, endTimeObj, yearID, pstEvent[i].EndTime.year);
					(*env)->SetIntField(env, endTimeObj, monthID, pstEvent[i].EndTime.month);
					(*env)->SetIntField(env, endTimeObj, mdayID, pstEvent[i].EndTime.mday);
					(*env)->SetIntField(env, endTimeObj, wdayID, pstEvent[i].EndTime.wday);
					(*env)->SetIntField(env, endTimeObj, hourID, pstEvent[i].EndTime.hour);
					(*env)->SetIntField(env, endTimeObj, minuteID, pstEvent[i].EndTime.minute);
					(*env)->SetIntField(env, endTimeObj, secondID, pstEvent[i].EndTime.second);
					(*env)->SetObjectField(env, EitObj, endTimeID, endTimeObj);

					jfieldID durationID = (*env)->GetFieldID(env, DVBEitInfoClass, "duration", "I");
					(*env)->SetIntField(env, EitObj, durationID, pstEvent[i].duration);
					
					jstring str1 = (*env)->NewStringUTF(env, pstEvent[i].lang);
					jfieldID langID = (*env)->GetFieldID(env, DVBEitInfoClass, "lang", "Ljava/lang/String;");
					(*env)->SetObjectField(env, EitObj, langID, str1);
					(*env)->DeleteLocalRef(env, str1);		
					
					str1 = (*env)->NewStringUTF(env, pstEvent[i].EventName);
					jfieldID EventNameID = (*env)->GetFieldID(env, DVBEitInfoClass, "EventName", "Ljava/lang/String;");
					(*env)->SetObjectField(env, EitObj, EventNameID, str1);
					(*env)->DeleteLocalRef(env, str1);		
					
					str1 = (*env)->NewStringUTF(env, pstEvent[i].Desc);
					jfieldID DescID = (*env)->GetFieldID(env, DVBEitInfoClass, "Desc", "Ljava/lang/String;");
					(*env)->SetObjectField(env, EitObj, DescID, str1);
					(*env)->DeleteLocalRef(env, str1);		
					
					str1 = (*env)->NewStringUTF(env, pstEvent[i].ExtendDesc);
					jfieldID ExtendDescID = (*env)->GetFieldID(env, DVBEitInfoClass, "ExtendDesc", "Ljava/lang/String;");
					(*env)->SetObjectField(env, EitObj, ExtendDescID, str1);
					(*env)->DeleteLocalRef(env, str1);		
					
					jfieldID running_statusID = (*env)->GetFieldID(env, DVBEitInfoClass, "running_status", "I");
					(*env)->SetIntField(env, EitObj, running_statusID, (jint)pstEvent[i].running_status);

					(*env)->SetObjectArrayElement(env, EitObjArray, i, EitObj);
					(*env)->DeleteLocalRef(env, EitObj);	
					(*env)->DeleteLocalRef(env, startTimeObj);		
					(*env)->DeleteLocalRef(env, endTimeObj);	
				}
					
				(*env)->DeleteLocalRef(env, DVBTimeInfoClass);		
				(*env)->DeleteLocalRef(env, DVBEitInfoClass);			
				free(pstEvent);
			}
			else
			{
				DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetScheduleInfo() - malloc pstEvent failed\r\n");
			}
		}
		else
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetScheduleInfo() - call DVBGetEitInfo return failed\r\n");
		}
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_GetEitInfo() - get DVBServiceInfo class failed\r\n");
	}

	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_GetScheduleInfo() - return\r\n");
	return EitObjArray;	
}

jint DVB_SetFrequencyTable(JNIEnv* env, jobject clazz, jobjectArray freqTable)
{
	jint ret = 0;
	dvb_frequency_t* pstFreqTable;
	unsigned int len;
	unsigned int i;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_SetFrequencyTable() - entry\r\n");
	len = (*env)->GetArrayLength(env, freqTable);
	if(DVBFreqInfoClass != NULL)
	{
		jfieldID ChannelID = (*env)->GetFieldID(env, DVBFreqInfoClass, "channel", "I");
		jfieldID frequencyID = (*env)->GetFieldID(env, DVBFreqInfoClass, "frequency", "I");
		jfieldID symID = (*env)->GetFieldID(env, DVBFreqInfoClass, "symbolRate", "I");
		jfieldID modID = (*env)->GetFieldID(env, DVBFreqInfoClass, "modulation", "I");
		jfieldID bandWidthID = (*env)->GetFieldID(env, DVBFreqInfoClass, "bandWidth", "I");
		jfieldID tunerTypeID = (*env)->GetFieldID(env, DVBFreqInfoClass, "tunerType", "I");

		pstFreqTable = (dvb_frequency_t*)malloc(len*sizeof(dvb_frequency_t));
		if(pstFreqTable)
		{
			for(i=0; i<len; i++)
			{
				jobject obj=(*env)->GetObjectArrayElement(env, freqTable, i);
				
				int channel = (*env)->GetIntField(env, obj, ChannelID);
				int frequency = (*env)->GetIntField(env, obj, frequencyID);
				int symbol_rate = (*env)->GetIntField(env, obj, symID);
				int modulation = (*env)->GetIntField(env, obj, modID);
				int bandwidth = (*env)->GetIntField(env, obj, bandWidthID);
				int type = (*env)->GetIntField(env, obj, tunerTypeID);

				pstFreqTable[i].channel = channel;
				pstFreqTable[i].frequency = frequency;
				pstFreqTable[i].symbol_rate = symbol_rate;
				pstFreqTable[i].modulation = modulation;
				pstFreqTable[i].bandwidth = bandwidth;
				pstFreqTable[i].tunertype = type;

				(*env)->DeleteLocalRef(env, obj);
			}
			ret = DVBSetFrequencyTable(pstFreqTable, len);
			if(ret != 0)
			{
				DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_SetFrequencyTable() - call DVBSetFrequencyTable failed\r\n");
			}
			free(pstFreqTable);
		}
		else
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_SetFrequencyTable() - malloc pstFreqTable failed\r\n");
			ret = -1;
		}
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_SetFrequencyTable() - find class DVBFreqInfo failed\r\n");
		ret = -1;
	}
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_SetFrequencyTable() - return\r\n");
	return ret;	
}

jint DVB_SetDVBPluginPath(JNIEnv* env, jobject clazz, jstring path)
{
	jint ret = 0;
	char *ps8PluginPath = ""; 
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_SetDVBPluginPath() - entry\r\n");
	
	if(path)
		ps8PluginPath = (char *)(*env)->GetStringUTFChars(env, path, NULL);
	ret = DVBSetDVBPluginPath(ps8PluginPath);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_SetDVBPluginPath() - return\r\n");
	return ret;		
}

void DVB_StopDVBService(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_StopDVBService() - entry\r\n");
	DVBStopDVBService();
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_StopDVBService() - return\r\n");
	return;	
}

void DVB_Standby(JNIEnv* env, jobject clazz)
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Standby() - entry\r\n");
	DVBTunerStandby();
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Standby() - return\r\n");
}

void DVB_Resume(JNIEnv* env, jobject clazz)
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Resume() - entry\r\n");
	DVBTunerResume();
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Resume() - return\r\n");
}

#include "backtrace.h"
#include "map_info.h"
#include <dlfcn.h>

#define PATH "/system/lib/libcorkscrew.so"  
#define BACKTRACE_FRAMES_MAX 0x64

typedef map_info_t* (*acquire_my_map_info_list_fun)();
typedef ssize_t (*unwind_backtrace_signal_arch_fun)(siginfo_t* siginfo, void* sigcontext, const map_info_t* map_info_list, backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
typedef void (*get_backtrace_symbols_fun)(const backtrace_frame_t* backtrace, size_t frames, backtrace_symbol_t* backtrace_symbols);
typedef void (*free_backtrace_symbols_fun)(backtrace_symbol_t* backtrace_symbols, size_t frames);
typedef void (*release_my_map_info_list_fun)(map_info_t* milist);

void dump_stack(int sig, siginfo_t* sig_info, void* ptr)
{
	int i;
	static backtrace_frame_t frames[BACKTRACE_FRAMES_MAX];
	static backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX];

	static void *gHandle = NULL;  
	acquire_my_map_info_list_fun acquire_my_map_info_list = NULL;  
	unwind_backtrace_signal_arch_fun unwind_backtrace_signal_arch = NULL;  
	get_backtrace_symbols_fun get_backtrace_symbols = NULL;  
	free_backtrace_symbols_fun free_backtrace_symbols = NULL;
	release_my_map_info_list_fun release_my_map_info_list = NULL;

	__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - entry, ptr = %p\r\n", ptr);

	if(gHandle == NULL) 
		gHandle = dlopen(PATH, RTLD_NOW);
	
	if(gHandle != NULL)
	{
		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - mwDLOpen OK\r\n");
		acquire_my_map_info_list = (acquire_my_map_info_list_fun)dlsym(gHandle, "acquire_my_map_info_list");  
		unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_fun)dlsym(gHandle, "unwind_backtrace_signal_arch");  
		get_backtrace_symbols = (get_backtrace_symbols_fun)dlsym(gHandle, "get_backtrace_symbols");  
		free_backtrace_symbols = (free_backtrace_symbols_fun)dlsym(gHandle, "free_backtrace_symbols");  
		release_my_map_info_list = (release_my_map_info_list_fun)dlsym(gHandle, "release_my_map_info_list");

		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - get fun end, acquire_my_map_info_list = %p, unwind_backtrace_signal_arch = %p, get_backtrace_symbols = %p, free_backtrace_symbols = %p, release_my_map_info_list = %p\r\n", 
			acquire_my_map_info_list, unwind_backtrace_signal_arch, get_backtrace_symbols, free_backtrace_symbols, release_my_map_info_list);
		if(acquire_my_map_info_list && unwind_backtrace_signal_arch && get_backtrace_symbols && free_backtrace_symbols && release_my_map_info_list)
		{
			map_info_t* info;
			ssize_t size;
			
			info = acquire_my_map_info_list();
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - acquire_my_map_info_list OK\r\n");
			size = unwind_backtrace_signal_arch(sig_info, ptr, info, frames, 0, BACKTRACE_FRAMES_MAX);
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - unwind_backtrace_signal_arch OK, size = %d\r\n", size);
			get_backtrace_symbols(frames, size, symbols);
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - get_backtrace_symbols OK\r\n");
			
			for (i = 0; i < size; i++)
			{
				backtrace_symbol_t symbol = symbols[i];
				// You could change the printf to fwrite if you want to save the info on disk
				__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "#%02d pc %08X  %s (%s+%d)",
				i,
				symbol.relative_pc,
				symbol.map_name ? symbol.map_name : "<unknown>",
				symbol.demangled_name ? symbol.demangled_name : symbol.symbol_name,
				symbol.relative_pc - symbol.relative_symbol_addr);
			}
			free_backtrace_symbols(symbols, size);
			release_my_map_info_list(info);
			dlclose(gHandle);
		}
		else
		{
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - get fun not OK, acquire_my_map_info_list = %p, unwind_backtrace_signal_arch = %p, get_backtrace_symbols = %p, free_backtrace_symbols = %p, release_my_map_info_list = %p\r\n", 
				acquire_my_map_info_list, unwind_backtrace_signal_arch, get_backtrace_symbols, free_backtrace_symbols, release_my_map_info_list);
		}
	}
	else
	{
		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "dump_stack() - open /system/lib/libcorkscrew.so failed\r\n");
	}
}


static struct sigaction old_actions[NSIG];

static const int monitored_signals[] = {
    SIGILL,
    SIGABRT,
    SIGBUS,
    SIGFPE,
    SIGSEGV,
#ifndef _MIPS_ARCH
    SIGSTKFLT,
#else
    SIGEMT,
#endif
    SIGPIPE
};

void DVB_CrashHandler(int signal, siginfo_t *info, void *reserved)
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_CrashHandler() - get signum %d!\r\n");
	old_actions[signal].sa_handler(signal);
	if(u32DebugOutputLevel != DVB_DEBUG_LEVEL_NONE)
	{
		dump_stack(signal, info, reserved);
		system("logcat -d -t 3000 -v time > backtraces.txt");
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_CrashHandler() - dump stack OK\r\n");
}

int DVB_CrashHandlerInit()
{
	struct sigaction handler; 
	unsigned int i = 0;
	
	memset(&handler, 0, sizeof(struct sigaction));  
	handler.sa_sigaction = DVB_CrashHandler;  
	handler.sa_flags = SA_SIGINFO | SA_ONSTACK;;   
	for (i = 0; i < sizeof(monitored_signals) / sizeof(int); ++i)  
	{       
		const int s = monitored_signals[i];    
		sigaction(s, &handler, &old_actions[s]); 
	}

	return 0;
}

jint DVB_Initialize(JNIEnv* env, jobject clazz)
{
	jint ret;
	char as8FilesDir[256];
	jobject context = getGlobalContext(env);

	memset(as8FilesDir, 0, sizeof(as8FilesDir));
	getAppFilesDir(context, env, as8FilesDir, sizeof(as8FilesDir)-1);
	DVBRegistorDebugFun(DVB_DebugOutput);
	ret = DVBInitialize(as8FilesDir);
	DVBRegistorCallback(DVBCallback);
	loaderInit(DVBCallback);

	gs_obj = (*env)->NewGlobalRef(env,clazz);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Initialize() - ret\r\n");
	return ret;
}

jint DVB_Terminate(JNIEnv* env, jobject clazz)
{
	jint ret = 0;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Terminate() - entry\r\n");
	
	ret = DVBTerminate();
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVB_Terminate() - return\r\n");
	return ret;
}

void DVB_DeviceStatusChanged(JNIEnv* env, jobject clazz, jchar status, jint fd)
{
	DVBDeviceStatusChanged(status, fd);
	return;
}


#define MAX_UNICODE_BYTE_NUM (512)
void DVBOpenSession(JNIEnv* env, jobject object)
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBOpenSession() - start\r\n");
	EnterMenu();
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBOpenSession() - end\r\n ");
}

 void DVBCloseSession(JNIEnv* env, jobject object)
 {
 	 DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBCloseSession() - start\r\n ");
 	 ShutDownSession();
	 DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBCloseSession() - end\r\n ");
 }

 void DVBSelectMenuItem(JNIEnv* env, jobject object, int index)
 {
 	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBSelectMenuItem() - start\r\n ");
 	GetIndex(index);
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBSelectMenuItem() - end\r\n ");
 }

void DVBSetPin(JNIEnv* env, jobject object, jstring pin)
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBSetPin() - start\r\n ");
	char* pch;
	if(pin)
		pch=(char*)(*env)->GetStringUTFChars(env,pin,NULL);
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBSetPin() - pin==NULL\r\n");
		return;
	}
	GetPin(pch);
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBSetPin() - end\r\n ");
}

jobject DVBGetCIMenuInfo(JNIEnv* env, jobject object)
{
	int i=0;
	char ptr_utf8[MAX_UNICODE_BYTE_NUM];
	menu_t* pmenu=NULL;
	jobject menu_obj=NULL;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetCIMenuInfo() - start\r\n ");
	if(NULL==(pmenu=GetPMenu()))
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetCIMenuInfo() - pmenu==NULL\r\n");
		return NULL;
	}
	if(DVBCIMenuInfoClass)
	{
		jmethodID cimenu_init=(*env)->GetMethodID(env,DVBCIMenuInfoClass,"<init>","()V");
		if(NULL==cimenu_init)
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetCIMenuInfo() - cimenu_init==NULL\r\n");
			return NULL;
		}
		menu_obj=(*env)->NewObject(env,DVBCIMenuInfoClass,cimenu_init);
		if(menu_obj!=NULL)
		{
			jfieldID  title_fid = (*env)->GetFieldID(env,DVBCIMenuInfoClass,"titleText","Ljava/lang/String;");
			jfieldID  sub_title_fid = (*env)->GetFieldID(env,DVBCIMenuInfoClass,"subTitleText","Ljava/lang/String;");
			jfieldID  btm_title_fid = (*env)->GetFieldID(env,DVBCIMenuInfoClass,"bottomText","Ljava/lang/String;");
			jfieldID  items_fid = (*env)->GetFieldID(env,DVBCIMenuInfoClass,"itemTextList","Ljava/util/ArrayList;");
			
			memset(ptr_utf8, 0, sizeof(ptr_utf8));
			memcpy(ptr_utf8,pmenu->m_title.m_text,pmenu->m_title.m_len);
			MmiConvertString((char*)ptr_utf8, pmenu->m_title.m_len);
			jstring str = (*env)->NewStringUTF(env,ptr_utf8);
			(*env)->SetObjectField(env,menu_obj,title_fid,str);
			(*env)->DeleteLocalRef(env, str);

			memset(ptr_utf8,0,sizeof(ptr_utf8));
			memcpy(ptr_utf8, pmenu->m_subtitle.m_text, pmenu->m_subtitle.m_len);
			MmiConvertString((char*)ptr_utf8, pmenu->m_subtitle.m_len);
			str = (*env)->NewStringUTF(env,ptr_utf8);
			(*env)->SetObjectField(env,menu_obj,sub_title_fid,str);
			(*env)->DeleteLocalRef(env, str);

			memset(ptr_utf8,0,sizeof(ptr_utf8));
			memcpy(ptr_utf8, pmenu->m_btmtitle.m_text,pmenu->m_btmtitle.m_len);
			MmiConvertString((char*)ptr_utf8, pmenu->m_btmtitle.m_len);
			str = (*env)->NewStringUTF(env,ptr_utf8);
			(*env)->SetObjectField(env,menu_obj,btm_title_fid,str);
			(*env)->DeleteLocalRef(env, str);
			
			jclass list_cls = (*env)->FindClass(env,"java/util/ArrayList");
			if(NULL == list_cls)
                     {
                     	DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetCIMenuInfo() - Can not FindClass list_cls\r\n");
						return NULL;
                 	}
			jmethodID ArrayList_init=(*env)->GetMethodID(env, list_cls, "<init>","()V");
			jmethodID ArrayList_add = (*env)->GetMethodID(env,list_cls,"add","(Ljava/lang/Object;)Z");
			jobject items_obj = (*env)->NewObject(env, list_cls, ArrayList_init);
			for (i=0; i<pmenu->m_cnt; i++)
			{
				jstring string;
				memset(ptr_utf8,0,sizeof(ptr_utf8));
				memcpy(ptr_utf8, ((pmenu->m_items)[i]).m_text, ((pmenu->m_items)[i]).m_len);
				MmiConvertString((char*)ptr_utf8, ((pmenu->m_items)[i]).m_len);
				string = (*env)->NewStringUTF(env,ptr_utf8);
				(*env)->CallBooleanMethod(env, items_obj, ArrayList_add, string);
				(*env)->DeleteLocalRef(env, string);
			}
			(*env)->SetObjectField(env, menu_obj, items_fid, items_obj);
		}
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetCIMenuInfo() - end\r\n ");
	return menu_obj;
}

jobject DVBGetCIPinInfo(JNIEnv* env,jobject object)
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetCIPinInfo() - start\r\n ");
	char ptr_utf8[512];
	mmiEnq_t *pmmiEnq;
	jobject menu_obj=NULL;
	if(NULL==(pmmiEnq=GetPEnq()))
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetCIPinInfo() - pmmiEnq==NULL\r\n");
		return NULL;
	}
	jmethodID cimenu_init=(*env)->GetMethodID(env,DVBCiPinInfoClass,"<init>","()V");
	menu_obj=(*env)->NewObject(env,DVBCiPinInfoClass,cimenu_init);
	if(menu_obj!=NULL)
	{
		jfieldID  blind_answer_fid = (*env)->GetFieldID(env,DVBCiPinInfoClass,"type","I");
		jfieldID  text_len_fid = (*env)->GetFieldID(env,DVBCiPinInfoClass,"length","I");
		jfieldID  enq_info_fid = (*env)->GetFieldID(env,DVBCiPinInfoClass,"title","Ljava/lang/String;");

		(*env)->SetIntField(env,menu_obj,blind_answer_fid,pmmiEnq->m_blind_answer);
		(*env)->SetIntField(env,menu_obj,text_len_fid,pmmiEnq->m_answer_text_len);

		memset(ptr_utf8, 0, sizeof(ptr_utf8));
		memcpy(ptr_utf8,pmmiEnq->m_enq.m_text,pmmiEnq->m_enq.m_len);
		MmiConvertString((char*)ptr_utf8,pmmiEnq->m_enq.m_len);
		jstring string = (*env)->NewStringUTF(env,ptr_utf8);
		(*env)->SetObjectField(env,menu_obj,enq_info_fid,string);
		(*env)->DeleteLocalRef(env,string);
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetCIPinInfo() - create DVBCIPinInfo object failed\r\n");
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetCIPinInfo() - end\r\n ");
	return menu_obj;
}

jobject DVBGetHardwareInfo(JNIEnv* env, jobject object)			
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetHardwareInfo() - start\r\n ");
	CIData HwInfo;
	char *pTem=NULL, tem[10];
	unsigned short data_len;
	memset(&HwInfo, 0, sizeof(CIData));
	memset(&tem,0,sizeof(tem));
	if((getDongleHw(&HwInfo, &data_len))==-1)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetHardwareInfo() - getDongleHw return -1\r\n");
		return NULL;
	}
	jobject CIDataObj=NULL;
	jmethodID CIDataInit=(*env)->GetMethodID(env,DVBCIDataClass,"<init>","()V");
	CIDataObj=(*env)->NewObject(env,DVBCIDataClass,CIDataInit);
	if(CIDataObj!=NULL)
	{
		jfieldID  deviceModelFid = (*env)->GetFieldID(env,DVBCIDataClass,"deviceModel","Ljava/lang/String;");
		jstring string = (*env)->NewStringUTF(env,HwInfo.deviceModel);
		(*env)->SetObjectField(env,CIDataObj,deviceModelFid ,string);
		(*env)->DeleteLocalRef(env,string);

		jfieldID  tunerTypeFid = (*env)->GetFieldID(env,DVBCIDataClass,"tunerType","I");
		pTem = strrchr(HwInfo.tunerType, ':');
		pTem++;
		strcpy(tem,pTem);
		pTem=strtok(HwInfo.tunerType,":");
		strcpy(HwInfo.tunerType,pTem);
		if((strcmp(tem,"Y"))==0)
		{
			if((strcmp(HwInfo.tunerType,"DTMB"))==0)
				(*env)->SetIntField(env,CIDataObj,tunerTypeFid,TUNER_TYPE_DTMB||TUNER_TYPE_DVBC);
			if((strcmp(HwInfo.tunerType,"DVBC"))==0)
				(*env)->SetIntField(env,CIDataObj,tunerTypeFid,TUNER_TYPE_DVBC);
			if((strcmp(HwInfo.tunerType,"DVBT"))==0)
				(*env)->SetIntField(env,CIDataObj,tunerTypeFid,TUNER_TYPE_DVBT||TUNER_TYPE_DVBC);
			if((strcmp(HwInfo.tunerType,"DVBT2"))==0)
				(*env)->SetIntField(env,CIDataObj,tunerTypeFid,TUNER_TYPE_DVBT2||TUNER_TYPE_DVBC);
			if((strcmp(HwInfo.tunerType,"DVBS"))==0)
				(*env)->SetIntField(env,CIDataObj,tunerTypeFid,TUNER_TYPE_DVBS||TUNER_TYPE_DVBC);
			if((strcmp(HwInfo.tunerType,"DVBS2"))==0)
				(*env)->SetIntField(env,CIDataObj,tunerTypeFid,TUNER_TYPE_DVBS2||TUNER_TYPE_DVBC);
		}

		jfieldID isDTCheckFid = (*env)->GetFieldID(env, DVBCIDataClass, "isDTCheck", "Z");
		if(strcmp(HwInfo.isDTCheck, "Y") == 0)
		{
			(*env)->SetBooleanField(env,CIDataObj, isDTCheckFid , true);
		}
		else
			(*env)->SetBooleanField(env,CIDataObj, isDTCheckFid , false);
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetHardwareInfo() - create DVBGetHardwareInfo object failed\r\n");
	}
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetHardwareInfo() - end\r\n ");
	return CIDataObj;
}

jobject DVBGetSmartCardInfo(JNIEnv* env, jobject object)		
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetSmartCardInfo() - start\r\n ");
	int ret=-1;
	CIData smartcard;
	memset(&smartcard,0,sizeof(CIData));
	getCardInfo(&smartcard);
	jobject CIDataObj=NULL;
	jmethodID CIDataInit=(*env)->GetMethodID(env,DVBCIDataClass,"<init>","()V");
	CIDataObj=(*env)->NewObject(env,DVBCIDataClass,CIDataInit);
	if(CIDataObj!=NULL)
	{
		jfieldID firmwareVersionFid = (*env)->GetFieldID(env,DVBCIDataClass,"firmwareVersion","Ljava/lang/String;");
		jstring string = (*env)->NewStringUTF(env,smartcard.firmwareVersion);
		(*env)->SetObjectField(env,CIDataObj,firmwareVersionFid,string);
		(*env)->DeleteLocalRef(env,string);

		jfieldID smartCardStatusFid = (*env)->GetFieldID(env,DVBCIDataClass,"smartCardStatus","I");
		if (strcmp(smartcard.Info, "no_smartcard") == 0)
		{
			(*env)->SetIntField(env,CIDataObj,smartCardStatusFid,SMART_CARD_UNINSTALLED);
		}
		else if (strcmp(smartcard.Info, "no smart") == 0)
		{
			(*env)->SetIntField(env,CIDataObj,smartCardStatusFid,SMART_CARD_INSTALLED_OK);
		}
		else if (strcmp(smartcard.Info, "installed_wrong") == 0)
		{
			(*env)->SetIntField(env,CIDataObj,smartCardStatusFid,SMART_CARD_INSTALLED_WRONG);
		}
		else if (strcmp(smartcard.Info, "invalid_smartcard") == 0)
		{
			(*env)->SetIntField(env,CIDataObj,smartCardStatusFid,SMART_CARD_INVALID);
		}
		else
		{
			jfieldID smartCardIdFid = (*env)->GetFieldID(env,DVBCIDataClass,"smartCardId","Ljava/lang/String;");
			jstring string = (*env)->NewStringUTF(env,smartcard.Info);
			(*env)->SetObjectField(env,CIDataObj,smartCardIdFid,string);
			(*env)->DeleteLocalRef(env,string);
		}
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetSmartCardInfo() - create DVBGetSmartCardInfo object failed\r\n");
	}
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetSmartCardInfo() - end \r\n ");
	return CIDataObj;
}

jobject DVBGetDeviceType(JNIEnv* env, jobject object)			
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetDeviceType() - start\r\n ");
	int ret=-1;
	char buffer[256];
	memset(buffer,0,sizeof(buffer));
	if((ret=getDeviceType(buffer))==-1)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetDeviceType() - getCardInfo return -1\r\n");
		return NULL;
	}
	jobject CIDataObj=NULL;
	jmethodID CIDataInit=(*env)->GetMethodID(env,DVBCIDataClass,"<init>","()V");
	CIDataObj=(*env)->NewObject(env,DVBCIDataClass,CIDataInit);
	if(CIDataObj!=NULL)
	{
		jfieldID  deviceTypeFid = (*env)->GetFieldID(env,DVBCIDataClass,"deviceType","Ljava/lang/String;");
		jstring string = (*env)->NewStringUTF(env,buffer);
		(*env)->SetObjectField(env,CIDataObj,deviceTypeFid,string);
		(*env)->DeleteLocalRef(env,string);
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetDeviceId() - create DVBGetDeviceId object failed\r\n");
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetDeviceType() - end \r\n ");
	return CIDataObj;
}

jobject DVBGetDeviceId(JNIEnv* env, jobject object)		
{
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetDeviceId() - start\r\n ");
	int ret=-1;
	char buffer[256];
	memset(buffer,0,sizeof(buffer));
	if((ret=getDeviceId(buffer))==-1)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetDeviceId() - getDeviceId return -1\r\n");
		return NULL;
	}
	jobject CIDataObj=NULL;
	jmethodID CIDataInit=(*env)->GetMethodID(env,DVBCIDataClass,"<init>","()V");
	CIDataObj=(*env)->NewObject(env,DVBCIDataClass,CIDataInit);
	if(CIDataObj!=NULL)
	{
		jfieldID  DeviceIdFid = (*env)->GetFieldID(env,DVBCIDataClass,"deviceId","Ljava/lang/String;");
		jstring string = (*env)->NewStringUTF(env,buffer);
		(*env)->SetObjectField(env,CIDataObj,DeviceIdFid,string);
		(*env)->DeleteLocalRef(env,string);
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBGetDeviceId() - create DVBGetDeviceId object failed\r\n");
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBGetDeviceId() - end \r\n ");
	return CIDataObj;
}

int DmxCallBack(unsigned long filterId,  unsigned char* pu8Data,unsigned short u16Datalen)
{
	jmethodID callback= NULL;
	JNIEnv *env = NULL;
	jclass clazz = NULL;

	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DmxCallBack() - start\r\n ");
	if((*gs_jvm)->AttachCurrentThread(gs_jvm,&env, NULL))
	{
		mwError("DmxCallBack() - AttachCurrentThread error\r\n");
		return ;
	}
	clazz = (*env)->GetObjectClass(env, gs_obj);
	if (NULL == clazz)
	{
		return ;
	}
	callback  = (*env)->GetMethodID(env,clazz,"jniDmxCallBack", "(I[B)I");
	if(callback == NULL)
	{
		mwError("DmxCallBack() - found jniDmxCallBack NULL\r\n");
		return ;
	}
	jbyteArray jbuffer	= (*env)->NewByteArray(env,  u16Datalen);
	(*env)->SetByteArrayRegion(env, jbuffer, 0, u16Datalen-1, (jbyte *)pu8Data);
	(*env)->CallIntMethod(env, gs_obj, callback, filterId, jbuffer);
	jthrowable exc = (*env)->ExceptionOccurred(env);
	if(exc)
	{
		(*env)->ExceptionDescribe(env);
		(*env)->ExceptionClear(env);
		jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
		if(newExcCls == NULL)
		{
			mwError("DmxCallBack() - found jniDmxCallBack NULL\r\n");
			return ;
		}
		(*env)->ThrowNew(env, newExcCls, "SingleFreqSearchCallback error!!");
		(*env)->DeleteLocalRef(env, newExcCls);
	}
	(*env)->DeleteLocalRef(env, clazz);
	(*env)->DeleteLocalRef(env, jbuffer);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DmxCallBack() - end \r\n ");
	return 0;
}

jint DVBStartDmxFilter(JNIEnv* env, jobject clazz, jobject DVBFilterParam)
{
	jint i,filterId=0;
	jclass DVBFilterParamClass;
	unsigned short au16SectByte[16];
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBStartDmxFilter() - start \r\n ");
	DVBFilterParamClass = (*env)->GetObjectClass(env, DVBFilterParam);
	if(DVBFilterParamClass)
	{
		jfieldID pidID = (*env)->GetFieldID(env, DVBFilterParamClass, "pid", "I");
		jfieldID crcCheckID = (*env)->GetFieldID(env, DVBFilterParamClass, "crcCheck", "I");
		jfieldID filterDepthID = (*env)->GetFieldID(env, DVBFilterParamClass, "filterDepth", "I");
		jfieldID dataID = (*env)->GetFieldID(env, DVBFilterParamClass, "data", "[B");
		jfieldID maskID = (*env)->GetFieldID(env, DVBFilterParamClass, "mask", "[B");

		unsigned short pid= (*env)->GetIntField(env, DVBFilterParam, pidID);
		unsigned int crcCheck = (*env)->GetIntField(env, DVBFilterParam, crcCheckID);
		unsigned short filterDepth = (*env)->GetIntField(env, DVBFilterParam, filterDepthID);
		jobject dataObject = (*env)->GetObjectField(env, DVBFilterParam, dataID);
		jobject maskObject = (*env)->GetObjectField(env, DVBFilterParam, maskID);

		jbyteArray * dataArray = (jbyteArray*)(&dataObject);
		jbyteArray * maskArray = (jbyteArray*)(&maskObject);
		unsigned char* data = (*env)->GetByteArrayElements(env, *dataArray, NULL);
		unsigned char* mask = (*env)->GetByteArrayElements(env, *maskArray, NULL);
		memset(au16SectByte, 0, sizeof(au16SectByte));
		if(filterDepth > sizeof(au16SectByte))
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBStartDmxFilter() - filterDepth > sizeof(au16SectByte) error\r\n");
			return -1;
		}
		for(i=0; i<filterDepth; i++)
		{
			//au16SectByte[i] = ((*env)->GetByteArrayElement(env, mask, i)<<8)|(*env)->GetByteArrayElement(env, data, i);
			au16SectByte[i] = mask[i]<<8;
			au16SectByte[i] = au16SectByte[i]|data[i];
		}

		(*env)->ReleaseByteArrayElements(env, *dataArray, data, 0);
		(*env)->ReleaseByteArrayElements(env, *maskArray, mask, 0);

		filterId = DvbStartFilter(pid, filterDepth, au16SectByte, crcCheck, DmxCallBack);
		if(filterId == -1)
		{
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVBStartDmxFilter() -error- filterId == -1\r\n");
		}
	}
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBStartDmxFilter() - end \r\n ");
	return filterId;	
}

jint DVBStopDmxFilter(JNIEnv* env, jobject clazz, int filterId)
{
	int s32Ret;
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBStopDmxFilter() - start \r\n ");
	s32Ret = DvbStopFilter(filterId);
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBStopDmxFilter() - end \r\n ");
}

void DVBSetFirmwareInfo(JNIEnv* env, jobject clazz,jstring SN, jstring filePath)
{
	unsigned char *sn = NULL;
	unsigned char *path = NULL;
	if(filePath) {
		sn = (char *)(*env)->GetStringUTFChars(env, SN, NULL);
		path = (char *)(*env)->GetStringUTFChars(env, filePath, NULL);
		loaderSetFirmwareInfo(sn, path);
		(*env)->ReleaseStringUTFChars(env, SN, sn);
		(*env)->ReleaseStringUTFChars(env, filePath, path);
		//(*env)->DeleteLocalRef(env, SN);
		//(*env)->DeleteLocalRef(env, filePath);
	} else {
		DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "DVBSetFirmwareInfo() error\r\n");
	}
}

static JNINativeMethod gMethods[] = 
{
	{"initialize",				"()I",											(void *)DVB_Initialize},
	{"resume",					"()V",											(void *)DVB_Resume},
	{"standby",					"()V",											(void *)DVB_Standby},
	{"terminate", 				"()I",											(void*)DVB_Terminate},
	{"setServiceGroupId", 		"(I)V",											(void*)DVB_SetServiceGroupId},
	{"getServiceGroupId", 		"()I",											(void*)DVB_GetServiceGroupId},
	{"restoreSettings", 		"()V",											(void*)DVB_RestoreSettings},
	{"getDVBTime", 				"()Lcom/smit/dvb/DVBTimeInfo;",						(void*)DVB_GetDVBTime},
	{"getAllServices", 			"()[Lcom/smit/dvb/DVBServiceInfo;",						(void*)DVB_GetAllServices},
	{"manualTune", 				"(Lcom/smit/dvb/DVBTunerInfo;)I",						(void*)DVB_ManualTune},
	{"startImportServices", 	"()V",											(void*)DVB_StartImportServices},
	{"importServices", 			"([Lcom/smit/dvb/DVBServiceInfo;IILjava/lang/String;)I",		(void*)DVB_ImportServices},
	{"finishImportServices", 	"()V",											(void*)DVB_FinishImportServices},
	{"manualScan", 				"(Lcom/smit/dvb/DVBTunerInfo;)I",						(void*)DVB_ManualScan},
	{"autoScan", 				"(II)I",											(void*)DVB_AutoScan},
	{"fullScan", 				"(II)I",											(void*)DVB_FullScan},
	{"abortScan", 				"()V",											(void*)DVB_AbortScan},
	{"playServiceByIndex", 		"(I)I",											(void*)DVB_PlayServiceByIndex},
	{"stopDVBService", 			"()V",											(void*)DVB_StopDVBService},
	{"getEitInfo", 				"(Lcom/smit/dvb/DVBServiceInfo;I)Lcom/smit/dvb/DVBEitInfo;",	(void*)DVB_GetEitInfo},
	{"getScheduleInfo", 		"(Lcom/smit/dvb/DVBServiceInfo;)[Lcom/smit/dvb/DVBEitInfo;",	(void*)DVB_GetScheduleInfo},
	{"setFrequencyTable", 		"([Lcom/smit/dvb/DVBFreqInfo;)V",						(void*)DVB_SetFrequencyTable},
	{"setDVBPluginPath", 		"(Ljava/lang/String;)V",								(void*)DVB_SetDVBPluginPath},
	{"deviceStatusChanged", 	"(BI)V",											(void*)DVB_DeviceStatusChanged},

	//ci
	{"openSession",				"()V", 											(void*)DVBOpenSession},
	{"closeSession",			"()V", 											(void*)DVBCloseSession},
	{"selectMenuItem",			"(I)V", 											(void*)DVBSelectMenuItem},
	{"setPin",					"(Ljava/lang/String;)V", 							(void*)DVBSetPin},
	{"getCIMenuInfo",			"()Lcom/smit/dvb/CIMenuInfo;",						(void*)DVBGetCIMenuInfo},
	{"getHardwareInfo",			"()Lcom/smit/dvb/CIData;",							(void*)DVBGetHardwareInfo},
	{"getSmartCardInfo",		"()Lcom/smit/dvb/CIData;",							(void*)DVBGetSmartCardInfo},
	{"getDeviceType",			"()Lcom/smit/dvb/CIData;",							(void*)DVBGetDeviceType},
	{"getDeviceId",				"()Lcom/smit/dvb/CIData;",							(void*)DVBGetDeviceId},
	{"getCIPinInfo",			"()Lcom/smit/dvb/CIPinInfo;",						(void*)DVBGetCIPinInfo},

	//
	{"startDmxFilter",			"(Lcom/smit/dvb/DVBFilterParam;)I",					(void*)DVBStartDmxFilter},
	{"stopDmxFilter",			"(I)I",											(void*)DVBStopDmxFilter},
	{"setFirmwareInfo",			"(Ljava/lang/String;Ljava/lang/String;)V",		(void *)DVBSetFirmwareInfo}
};


static int DVB_RegisterMethods (JNIEnv *env)
{
	jclass clazz;
	
	clazz = (*env)->FindClass(env, CLASS_PATH);
	if (clazz == NULL) 
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_RegisterMethods() - unable to find class\r\n'");
		return JNI_FALSE;
	}
	
	if ((*env)->RegisterNatives(env, clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR,"DVB_RegisterMethods() - RegisterNatives failed\r\n'");
		if ((*env)->ExceptionCheck(env))//clear exception
		{
			(*env)->ExceptionClear(env);
			DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_RegisterMethods() - found exception, native method may not founded int JAVA\r\n");
		}
		(*env)->DeleteLocalRef(env, clazz);
		return JNI_FALSE;
	}

	(*env)->DeleteLocalRef(env, clazz);
	return JNI_TRUE;
}

int DVB_FindClass(JNIEnv *env)
{
	jclass tmpClass;
	jmethodID tmpMethodID;
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - entry\r\n");
	
	tmpClass = (*env)->FindClass(env, "com/smit/dvb/DVBTunerInfo");
	if(tmpClass == NULL)
	{
		mwError("DVB_FindClass() - com/smit/dvb/DVBTunerInfo error\r\n");
	}
	else
	{
		DVBTunerInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}
	
	tmpClass = (*env)->FindClass(env, "com/smit/dvb/DVBNetworkInfo");
	if(tmpClass == NULL)
	{
		mwError("DVB_FindClass() - com/smit/dvb/DVBNetworkInfo error\r\n");
	}
	else
	{
		DVBNetworkInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}
	
	tmpClass = (*env)->FindClass(env, "com/smit/dvb/DVBServiceInfo");
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/DVBServiceInfo error\r\n");
	}
	else
	{
		DVBServiceInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}
	
	tmpClass = (*env)->FindClass(env, "com/smit/dvb/DVBTimeInfo");\
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/DVBTimeInfo error\r\n");
	}
	else
	{
		DVBTimeInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}
	
	tmpClass = (*env)->FindClass(env, "com/smit/dvb/DVBEitInfo");
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/DVBEitInfo error\r\n");
	}
	else
	{
		DVBEitInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}
	
	tmpClass = (*env)->FindClass(env, "com/smit/dvb/DVBFreqInfo");
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/DVBFreqInfo error\r\n");
	}
	else
	{
		DVBFreqInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}

	tmpClass = (*env)->FindClass(env, "com/smit/dvb/CIMenuInfo");
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/CIMenuInfo error\r\n");
	}
	else
	{
		DVBCIMenuInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}

	tmpClass = (*env)->FindClass(env, "com/smit/dvb/CIPinInfo");
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/CIPinInfo error\r\n");
	}
	else
	{
		DVBCiPinInfoClass = (*env)->NewGlobalRef(env, tmpClass);
	}

	tmpClass = (*env)->FindClass(env, "com/smit/dvb/CIData");
	if(tmpClass == NULL)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - com/smit/dvb/CIPinInfo error\r\n");
	}
	else
	{
		DVBCIDataClass = (*env)->NewGlobalRef(env, tmpClass);
	}

	DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "DVB_FindClass() - NewGlobalRef class OK\r\n");
	return 0;
}

int DVB_UnRefClasses(JNIEnv *env)
{
	(*env)->DeleteGlobalRef(env, DVBTunerInfoClass);
	//(*env)->DeleteGlobalRef(env, DVBNetworkInfoClass);
	(*env)->DeleteGlobalRef(env, DVBServiceInfoClass);
	(*env)->DeleteGlobalRef(env, DVBTimeInfoClass);
	(*env)->DeleteGlobalRef(env, DVBEitInfoClass);
	(*env)->DeleteGlobalRef(env, DVBFreqInfoClass);
	(*env)->DeleteGlobalRef(env,DVBCiPinInfoClass);
	(*env)->DeleteGlobalRef(env,DVBCIMenuInfoClass);
	(*env)->DeleteGlobalRef(env,DVBCIDataClass);
	
	return 0;
}

jint JNI_OnLoad (JavaVM *vm, void *reserved)
{
	JNIEnv 	*env = NULL;
	jint		 result = -1;

	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "JNI_OnLoad() - entry\r\n");
	if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK) {
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "JNI_OnLoad() - ERROR: GetEnv failed\n");
		goto fail;
	}

	if((*env)->GetJavaVM(env,&gs_jvm) != JNI_OK)
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "JNI_OnLoad() - ERROR: GetJavaVM failed\n");
		goto fail;
	}

	if (DVB_RegisterMethods(env) < 0) {
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "JNI_OnLoad() - ERROR: register_android_dvb_methods failed\n");
	}

	DVB_FindClass(env);
	
	DVB_DebugOutput(DVB_DEBUG_LEVEL_COMMON, "JNI_OnLoad() - finish");
	result = JNI_VERSION_1_4;

fail:
	return result;
}

void JNI_OnUnload(JavaVM *vm, void *reserved)
{
	JNIEnv 	*env = NULL;
	
	if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK)
	{
		DVB_UnRefClasses(env);
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "JNI_OnLoad() - DVB_UnRefClasses OK\r\n");
	}
	else
	{
		DVB_DebugOutput(DVB_DEBUG_LEVEL_ERROR, "JNI_OnLoad() - GetEnv failed\r\n");
	}
}



